import os
from pmapi import config
import subprocess
from pmapi import progbar


def clone(source_url: str, dist_dir: str, depth: int = 0, prog_text: str = "", progress_callback=lambda **kwargs: None, progress_callback_args: dict = {}) -> int:
    depth_arg = ("" if depth == 0 else f"--depth={str(depth)}")  # clone深度参数
    rcommands = f"{config.GITSHELL} clone {source_url} " + \
        f"{dist_dir} {depth_arg} --progress"  # 运行命令
    env = os.environ.copy()
    env["LANG"] = "en_US"  # 设置语言
    pipes = subprocess.Popen(rcommands,
                             shell=True,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             env=env)  # 运行
    cache = ""  # 读取缓存
    # 进度条模板
    tmpl_text = "Get: {prog_text} [{bar}] {prog}%".format(
        prog_text='/'.join(
            source_url.split("/")[-2:]).split(".")[0]+" "*max(
            30-len('/'.join(
                source_url.split("/")[-2:]).split(".")[0]), 0), bar="{bar}", prog="{prog}")
    prog = progbar.ProgressBar(templete=tmpl_text, barlen=25)  # 进度条

    progress = 0

    def ref_prog():  # 刷新进度
        progress_callback(**progress_callback_args,
                          progress=progress, mode="clone")
        prog.set(progress)
    ref_prog()
    ret = 0
    while pipes.poll() is None:  # 判断程序是否结束
        nowchar = pipes.stderr.read(1).decode()  # 读字符
        if nowchar in ('\r', '\n'):  # 回车
            if "fatal: " in cache:
                ret = 2
                tmpl_text = "Ign: {prog_text} -{bar}- {prog}%".format(
                    prog_text='/'.join(
                        source_url.split("/")[-2:]).split(".")[0]+" "*max(
                        30-len('/'.join(
                            source_url.split("/")[-2:]).split(".")[0]), 0), bar="{bar}", prog="{prog}")
                prog.templete = tmpl_text
                prog.p_templete = ("-", "-")
                prog.set(100)
                break
            cache = cache.replace("remote: ", "")
            cache = cache.split(",")[0]
            if "Cloning into" in cache:
                cache = ""
                continue
            if "Total " in cache:  # 显示总计，clone结束
                progress = 100
                ref_prog()
                break
            try:
                stat, prog_tmp = cache.split(":")  # 状态，当前进度（文本）
                assert prog_tmp.split("%")[0].lstrip(
                    " ") != "You appear to have cloned an empty repository."  # 仓库为空，忽略
                prog_now = int(prog_tmp.split("%")[0].lstrip(" "))  # 当前进度
            except:  # 忽略输出
                tmpl_text = "Ign: {prog_text} -{bar}- {prog}%".format(
                    prog_text='/'.join(
                        source_url.split("/")[-2:]).split(".")[0]+" "*max(
                        30-len('/'.join(
                            source_url.split("/")[-2:]).split(".")[0]), 0), bar="{bar}", prog="{prog}")
                prog.templete = tmpl_text
                prog.p_templete = ("-", "-")
                prog.set(100)
                ret = 1
                break
            if stat == "Enumerating objects":  # 计数
                progress = 5
                ref_prog()
            elif stat == "Receiving objects":  # 下载
                progress = int(prog_now*0.9)+5
                ref_prog()
            elif stat == "Resolving deltas":  # 统计对象
                progress = 99
                ref_prog()
            elif stat == "Updating files":  # 统计对象
                progress = 100
                ref_prog()
            cache = ""
        else:
            cache = cache + nowchar  # 写缓存
    return ret


def pull(dist_dir: str, depth: int = 0, progress_callback=lambda **kwargs: None, progress_callback_args: dict = {}) -> int:
    depth_arg = ("" if depth == 0 else f"--depth={str(depth)}")
    rcommands = f"cd \"{dist_dir.replace('/', os.sep)}\"&{config.GITSHELL}" + \
        f" pull -f {depth_arg} -q --progress"
    env = os.environ.copy()
    env["LANG"] = "en_US"
    pipes = subprocess.Popen(rcommands,
                             shell=True,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             env=env)  # 运行
    cache = ""  # 读取缓存
    # 进度条模板
    tmpl_text = "Upd: {prog_text} [{bar}] {prog}%".format(
        prog_text=(dist_dir.split("/")[-1]).split(".")[0]+" "*max(
            30-len((dist_dir.split("/")[-1]).split(".")[0]), 0), bar="{bar}", prog="{prog}")
    prog = progbar.ProgressBar(templete=tmpl_text, barlen=25)  # 进度条

    progress = 0

    def ref_prog():  # 刷新进度
        progress_callback(**progress_callback_args,
                          progress=progress, mode="pull")
        prog.set(progress)
    ref_prog()
    while pipes.poll() is None:  # 判断程序是否结束
        nowchar = pipes.stderr.read(1).decode()  # 读字符
        if nowchar in ('\r', '\n'):  # 回车
            cache = cache.replace("remote: ", "")
            cache = cache.replace(", done.", "")
            if "Total " in cache:  # 显示总计，clone结束
                progress = 100
                ref_prog()
                break
            try:
                stat, prog_tmp = cache.split(":")  # 状态，当前进度（文本）
                assert "Your configuration specifies to merge" in prog_tmp.split("%")[0].lstrip(
                    " ")  # 仓库为空，忽略
                prog_now = int(prog_tmp.split("%")[0].lstrip(" "))  # 当前进度
            except:  # 忽略输出
                tmpl_text = "Ign: {prog_text} -{bar}- {prog}%".format(
                    prog_text=(dist_dir.split("/")[-1]).split(".")[0]+" "*max(
                        30-len((dist_dir.split("/")[-1]).split(".")[0]), 0), bar="{bar}", prog="{prog}")
                prog.templete = tmpl_text
                prog.p_templete = ("-", "-")
                prog.set(100)
                break
            if stat == "Enumerating objects":  # 计数
                progress = 5
                ref_prog()
            elif stat == "Counting objects":  # 统计对象
                progress = int(prog_now*0.45)+10
                ref_prog()
            elif stat == "Writing object":  # 写入对象
                progress = int(prog_now*0.45)+55
                ref_prog()
            cache = ""
        else:
            cache = cache + nowchar  # 写缓存
    progress = 100  # 无需更新
    ref_prog()
    pipes.wait()
